// Copyright 2012 dmitry.a.novikov@gmail.com
// 
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// 
// http://www.apache.org/licenses/LICENSE-2.0
// 
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Smart pointers


#ifndef _INCLUDED_CNZ_PTR_H_
#define _INCLUDED_CNZ_PTR_H_


namespace CnsZ {

  enum PtrMode { DoNotAddRef };

  // Smart pointer template
  template<class T>
  class P {
  protected:
    void conctruct(const T* p) {
      ptr=p;
      if(p)
        p->addRef();
    }
    void assign(const T* p) {
      if(ptr)
        ptr->release();
      ptr = p;
      if(ptr)
        ptr->addRef();
    }
    const T* ptr;
  public:
    P() : ptr(0) {}
    ~P() {
      if(ptr)
        ptr->release();
    }
    P(const P& p) { conctruct(p.get()); }
    P(const T* p) { conctruct(p); }
    P(const T* p, PtrMode ) : ptr(p) {}
    P& operator =(const P& p) {
      assign(const_cast<T*>(p.get()));
      return *this;
    }
    P& operator =(T* p) {
      assign(const_cast<T*>(p));
      return *this;
    }

    const T* get() const { return ptr; }
    T* get() { return const_cast<T*>(ptr); }

    operator T*() { return get(); }
    operator const T*() const { return get(); }

    T* operator->() { return const_cast<T*>(ptr); }
    const T* operator->() const { return ptr; }

    T* detach() {
      T* p = get();
      ptr = 0;
      return p;
    }
  };

}

#endif //#ifndef _INCLUDED_CNZ_PTR_H_